package com.example.onlinemonitoring.autoRun;

import com.example.onlinemonitoring.SpringUtil;
import com.example.onlinemonitoring.Util.CommPortManager;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import lombok.Data;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;

/**
 * ComTcp的作用与串口服务器通讯，用服务器作为桥梁连接工控机串口
 */
@Data
public class ComTcp implements Runnable {
    // 客户端socket
    public Socket s;
    // socket的输出流，用于发送数据
    public OutputStream outputStream = null;
    // socket的输入流，用于接收数据
    InputStream inputStream = null;
    // 服务器端口号
    int port;
    // 设备索引（或ID）
    int index = -1;
    // 连接状态标志
    boolean conn;
    // 运行状态标志
    public boolean isrunning = false;
    // 发送线程运行状态标志
    public boolean sendrun = false;
    // 接收线程运行状态标志
    public boolean recvrun = false;
    // 应用上下文（用于获取Spring容器中的bean）
    private ApplicationContext context;
    // 输入流的字符流读取器，用于读取字符数据
    InputStreamReader inputStreamReader;
    // 缓冲读取器，用于提高字符读取效率
    BufferedReader br;
    // 串口列表字符串，用于存储串口信息
    public String serieslist = "";
    // 存储设备打开或关闭状态的映射
    public HashMap<Integer, Integer> openOrCloseMap = new HashMap<>();
    // 串口通信运行器引用
    private ComRunner comrunner;

    // 尝试连接到串口服务器并初始化资源
    public boolean load() {
        try {
            // 创建Socket连接
            s = new Socket("127.0.0.1", port);
            // 获取输出流
            outputStream = s.getOutputStream();
            // 获取输入流
            inputStream = s.getInputStream();
            // 创建输入流的字符流读取器
            inputStreamReader = new InputStreamReader(inputStream);
            // 创建字符流的缓冲读取器
            br = new BufferedReader(inputStreamReader);
            System.out.println("连接串口服务器成功！");
            // 如果comrunner为空，则从Spring容器中获取它
            if (comrunner == null) {
                comrunner = (ComRunner) SpringUtil.getBean("comRunner");
            }
            // 设置发送和接收线程的运行状态为true
            sendrun = true;
            recvrun = true;
            // 运行设备应用
            comrunner.runAppdevice(index);
            return true;
        } catch (IOException e) {
            System.out.println("连接串口服务器失败,请重启程序！");
            isrunning = false;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }
        return false;
    }

    // 发送指令到串口
    public boolean send(String cmd) {
        if (sendrun) {
            byte[] buffer;
            try {
                System.out.println("cmd:  " + cmd);
                // 将字符串指令转换为UTF-8字节码
                buffer = cmd.getBytes("UTF8");
                // 添加换行符到指令末尾
                buffer = byteConcat(buffer, new byte[] { 0x0a });
                // 写入指令到输出流
                outputStream.write(buffer, 0, buffer.length);
                // 刷新输出流，确保数据发送
                outputStream.flush();
            } catch (UnsupportedEncodingException e) {
                return false;
            } catch (IOException e) {
                return false;
            }
            return true;
        }
        return false;
    }

    // 实现Runnable接口的run方法，用于接收数据
    @Override
    public void run() {
        while (true) {
            try {
                String str;
                // 检查缓冲读取器是否为空
                if (br == null) {
                    throw new Exception();
                }
                // 读取一行数据
                str = br.readLine();

                // 如果读取的数据为空或者是空字符串，终止循环
                if (str == null || str.equals("")) {
                    return;
                }
                // 解析接收到的数据
                String[] strlist = str.split(",");
                // 如果数据长度不符合要求，终止循环
                if (strlist.length <= 1) {
                    return;
                }
                // 根据接收到的数据第一部分的内容执行相应的操作
                switch (strlist[0]) {
                    case "OPEN":
                        if (strlist[3].equals("0") || strlist[3].equals("3")) {
                            openOrCloseMap.put(index, 1);
                            ComRunner.devmap.get(index).setIsrun(true);
                            if ((ComRunner.devmap.get(index).getIssend().get(Thread.currentThread().getId()) == null)) {
                                ComRunner.devmap.get(index).startSendThread(ComRunner.devmap.get(index).getAd());
                            }
                            ComRunner.devmap.get(index).setText("开启串口成功");
                        } else {
                            openOrCloseMap.put(index, 0);
                            ComRunner.devmap.get(index).setText("开启串口失败");
                            // 将设备实时表的通信状态改为异常
                        }
                        break;
                    case "RECV":
                        if (ComRunner.devmap.containsKey(index)) {

                            ComRunner.devmap.get(index).recv(strlist[1].toUpperCase());

                        }
                        break;
                    case "CLOSE":
                        if (strlist[1].equals("97")) {// 下发的关闭命令错误，很可能丢包了
                            openOrCloseMap.put(index, 1);
                            ComRunner.devmap.get(index).setText("关闭串口失败");
                        } else if (strlist[1].equals("0")) {// 成功关闭
                            openOrCloseMap.put(index, 0);
                            ComRunner.devmap.get(index).Close();
                            ComRunner.devmap.get(index).setText("关闭串口成功");
                            ComRunner.devmap.get(index).setIsrun(false);
                        } else if (strlist[1].equals("1")) {// 关闭以后判断串口并未关闭，所以关闭失败了，未知原因
                            openOrCloseMap.put(index, 1);
                            ComRunner.devmap.get(index).setText("关闭串口失败");
                        } else {// 串口因为其他原因关闭了，所以返回关闭成功
                            openOrCloseMap.put(index, 0);
                            ComRunner.devmap.get(index).Close();
                            ComRunner.devmap.get(index).setText("关闭串口成功");
                            ComRunner.devmap.get(index).setIsrun(false);

                        }

                        break;
                    case "ISAVA":
                        if (!strlist[2].equals("97") && !strlist[2].equals("1")) {
                            if (strlist[1].equals("0")) {
                                ComRunner.devmap.get(index).setAvailableRet(true);
                            } else {
                                ComRunner.devmap.get(index).setAvailableRet(false);
                            }
                        }
                        break;
                    case "INFO":
                        serieslist = strlist[1];// INFO,COM1|COM10|COM11|COM4|COM5|COM2|COM3|,0
                        break;
                    default:
                        break;
                }
            } catch (NullPointerException e) {
                e.printStackTrace();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            } catch (Exception e) {
                if (ComRunner.devmap.get(index) != null) {
                    openOrCloseMap.put(index, 0);
                    ComRunner.devmap.get(index).Close();
                    ComRunner.devmap.get(index).setText("关闭串口成功");
                    ComRunner.devmap.get(index).setIsrun(false);
                }

                sendrun = false;
                load();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }
        }
    }

    // 将两个字节数组合并成一个字节数组
    public static byte[] byteConcat(byte[] bt1, byte[] bt2) {
        byte[] bt4 = new byte[bt1.length + bt2.length];
        int len = 0;
        // 复制第一个数组到新数组
        System.arraycopy(bt1, 0, bt4, 0, bt1.length);
        len += bt1.length;
        // 复制第二个数组到新数组
        System.arraycopy(bt2, 0, bt4, len, bt2.length);
        return bt4;
    }
}
